//-
// ==========================================================================
// Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk
// license agreement provided at the time of installation or download,
// or which otherwise accompanies this software in either electronic
// or hard copy form.
// ==========================================================================
//+

// DISCLAIMER: THIS PLUGIN IS PROVIDED AS IS.  IT IS NOT SUPPORTED BY

//            AUTODESK, SO PLEASE USE AND MODIFY AT YOUR OWN RISK.

//

// PLUGIN NAME: closestPointOnCurve v1.0

// FILE: closestPointOnCurveNode.cpp

// DESCRIPTION: -Defines "closestPointOnCurve" node.

//              -Please see readme.txt for full details.

// AUTHOR: QT

// REFERENCES: -This plugin's concept is based off of the "closestPointOnSurface" node.

//             -The MEL script AEclosestPointOnSurfaceTemplate.mel was referred to for

//              the AE template MEL script that accompanies the closestPointOnCurve node.

// LAST UPDATED: Oct. 13th, 2001.

// COMPILED AND TESTED ON: Maya 4.0 on Windows





// HEADER FILES:

#include "closestPointOnCurveNode.h"

#include "closestTangentUAndDistance.h"





// DEFINE CLASS'S STATIC DATA MEMBERS:

MTypeId closestPointOnCurveNode::id(0x00105482);

MObject closestPointOnCurveNode::aInCurve;

MObject closestPointOnCurveNode::aInPosition;

MObject closestPointOnCurveNode::aInPositionX;

MObject closestPointOnCurveNode::aInPositionY;

MObject closestPointOnCurveNode::aInPositionZ;

MObject closestPointOnCurveNode::aPosition;

MObject closestPointOnCurveNode::aPositionX;

MObject closestPointOnCurveNode::aPositionY;

MObject closestPointOnCurveNode::aPositionZ;

MObject closestPointOnCurveNode::aNormal;

MObject closestPointOnCurveNode::aNormalX;

MObject closestPointOnCurveNode::aNormalY;

MObject closestPointOnCurveNode::aNormalZ;

MObject closestPointOnCurveNode::aTangent;

MObject closestPointOnCurveNode::aTangentX;

MObject closestPointOnCurveNode::aTangentY;

MObject closestPointOnCurveNode::aTangentZ;

MObject closestPointOnCurveNode::aParamU;

MObject closestPointOnCurveNode::aDistance;





// CONSTRUCTOR DEFINITION:

closestPointOnCurveNode::closestPointOnCurveNode()

{

}





// DESTRUCTOR DEFINITION:

closestPointOnCurveNode::~closestPointOnCurveNode()

{

}





// FOR CREATING AN INSTANCE OF THIS NODE:

void *closestPointOnCurveNode::creator()

{

   return new closestPointOnCurveNode();

}





// INITIALIZES THE NODE BY CREATING ITS ATTRIBUTES:

MStatus closestPointOnCurveNode::initialize()

{

   // CREATE AND ADD ".inCurve" ATTRIBUTE:

   MFnTypedAttribute inCurveAttrFn;

   aInCurve = inCurveAttrFn.create("inCurve", "ic", MFnData::kNurbsCurve);

   inCurveAttrFn.setStorable(true);

   inCurveAttrFn.setKeyable(false);

   inCurveAttrFn.setReadable(true);

   inCurveAttrFn.setWritable(true);

   inCurveAttrFn.setCached(false);

   addAttribute(aInCurve);



   // CREATE AND ADD ".inPositionX" ATTRIBUTE:

   MFnNumericAttribute inPositionXAttrFn;

   aInPositionX = inPositionXAttrFn.create("inPositionX", "ipx", MFnNumericData::kDouble, 0.0);

   inPositionXAttrFn.setStorable(true);

   inPositionXAttrFn.setKeyable(true);

   inPositionXAttrFn.setReadable(true);

   inPositionXAttrFn.setWritable(true);

   addAttribute(aInPositionX);



   // CREATE AND ADD ".inPositionY" ATTRIBUTE:

   MFnNumericAttribute inPositionYAttrFn;

   aInPositionY = inPositionYAttrFn.create("inPositionY", "ipy", MFnNumericData::kDouble, 0.0);

   inPositionYAttrFn.setStorable(true);

   inPositionYAttrFn.setKeyable(true);

   inPositionYAttrFn.setReadable(true);

   inPositionYAttrFn.setWritable(true);

   addAttribute(aInPositionY);



   // CREATE AND ADD ".inPositionZ" ATTRIBUTE:

   MFnNumericAttribute inPositionZAttrFn;

   aInPositionZ = inPositionZAttrFn.create("inPositionZ", "ipz", MFnNumericData::kDouble, 0.0);

   inPositionZAttrFn.setStorable(true);

   inPositionZAttrFn.setKeyable(true);

   inPositionZAttrFn.setReadable(true);

   inPositionZAttrFn.setWritable(true);

   addAttribute(aInPositionZ);



   // CREATE AND ADD ".inPosition" ATTRIBUTE:

   MFnNumericAttribute inPositionAttrFn;

   aInPosition = inPositionAttrFn.create("inPosition", "ip", aInPositionX, aInPositionY, aInPositionZ);

   inPositionAttrFn.setStorable(true);

   inPositionAttrFn.setKeyable(true);

   inPositionAttrFn.setReadable(true);

   inPositionAttrFn.setWritable(true);

   addAttribute(aInPosition);



   // CREATE AND ADD ".positionX" ATTRIBUTE:

   MFnNumericAttribute pointXAttrFn;

   aPositionX = pointXAttrFn.create("positionX", "px", MFnNumericData::kDouble, 0.0);

   pointXAttrFn.setStorable(false);

   pointXAttrFn.setKeyable(false);

   pointXAttrFn.setReadable(true);

   pointXAttrFn.setWritable(false);

   addAttribute(aPositionX);



   // CREATE AND ADD ".positionY" ATTRIBUTE:

   MFnNumericAttribute pointYAttrFn;

   aPositionY = pointYAttrFn.create("positionY", "py", MFnNumericData::kDouble, 0.0);

   pointYAttrFn.setStorable(false);

   pointYAttrFn.setKeyable(false);

   pointYAttrFn.setReadable(true);

   pointYAttrFn.setWritable(false);

   addAttribute(aPositionY);



   // CREATE AND ADD ".positionZ" ATTRIBUTE:

   MFnNumericAttribute pointZAttrFn;

   aPositionZ = pointZAttrFn.create("positionZ", "pz", MFnNumericData::kDouble, 0.0);

   pointZAttrFn.setStorable(false);

   pointZAttrFn.setKeyable(false);

   pointZAttrFn.setReadable(true);

   pointZAttrFn.setWritable(false);

   addAttribute(aPositionZ);



   // CREATE AND ADD ".position" ATTRIBUTE:

   MFnNumericAttribute pointAttrFn;

   aPosition = pointAttrFn.create("position", "p", aPositionX, aPositionY, aPositionZ);

   pointAttrFn.setStorable(false);

   pointAttrFn.setKeyable(false);

   pointAttrFn.setReadable(true);

   pointAttrFn.setWritable(false);

   addAttribute(aPosition);



   // CREATE AND ADD ".normalX" ATTRIBUTE:

   MFnNumericAttribute normalXAttrFn;

   aNormalX = normalXAttrFn.create("normalX", "nx", MFnNumericData::kDouble, 0.0);

   normalXAttrFn.setStorable(false);

   normalXAttrFn.setKeyable(false);

   normalXAttrFn.setReadable(true);

   normalXAttrFn.setWritable(false);

   addAttribute(aNormalX);



   // CREATE AND ADD ".normalY" ATTRIBUTE:

   MFnNumericAttribute normalYAttrFn;

   aNormalY = normalYAttrFn.create("normalY", "ny", MFnNumericData::kDouble, 0.0);

   normalYAttrFn.setStorable(false);

   normalYAttrFn.setKeyable(false);

   normalYAttrFn.setReadable(true);

   normalYAttrFn.setWritable(false);

   addAttribute(aNormalY);



   // CREATE AND ADD ".normalZ" ATTRIBUTE:

   MFnNumericAttribute normalZAttrFn;

   aNormalZ = normalZAttrFn.create("normalZ", "nz", MFnNumericData::kDouble, 0.0);

   normalZAttrFn.setStorable(false);

   normalZAttrFn.setKeyable(false);

   normalZAttrFn.setReadable(true);

   normalZAttrFn.setWritable(false);

   addAttribute(aNormalZ);



   // CREATE AND ADD ".normal" ATTRIBUTE:

   MFnNumericAttribute normalAttrFn;

   aNormal = normalAttrFn.create("normal", "n", aNormalX, aNormalY, aNormalZ);

   normalAttrFn.setStorable(false);

   normalAttrFn.setKeyable(false);

   normalAttrFn.setReadable(true);

   normalAttrFn.setWritable(false);

   addAttribute(aNormal);



   // CREATE AND ADD ".tangentX" ATTRIBUTE:

   MFnNumericAttribute tangentXAttrFn;

   aTangentX = tangentXAttrFn.create("tangentX", "tx", MFnNumericData::kDouble, 0.0);

   tangentXAttrFn.setStorable(false);

   tangentXAttrFn.setKeyable(false);

   tangentXAttrFn.setReadable(true);

   tangentXAttrFn.setWritable(false);

   addAttribute(aTangentX);



   // CREATE AND ADD ".tangentY" ATTRIBUTE:

   MFnNumericAttribute tangentYAttrFn;

   aTangentY = tangentYAttrFn.create("tangentY", "ty", MFnNumericData::kDouble, 0.0);

   tangentYAttrFn.setStorable(false);

   tangentYAttrFn.setKeyable(false);

   tangentYAttrFn.setReadable(true);

   tangentYAttrFn.setWritable(false);

   addAttribute(aTangentY);



   // CREATE AND ADD ".tangentZ" ATTRIBUTE:

   MFnNumericAttribute tangentZAttrFn;

   aTangentZ = tangentZAttrFn.create("tangentZ", "tz", MFnNumericData::kDouble, 0.0);

   tangentZAttrFn.setStorable(false);

   tangentZAttrFn.setKeyable(false);

   tangentZAttrFn.setReadable(true);

   tangentZAttrFn.setWritable(false);

   addAttribute(aTangentZ);



   // CREATE AND ADD ".tangent" ATTRIBUTE:

   MFnNumericAttribute tangentAttrFn;

   aTangent = tangentAttrFn.create("tangent", "t", aTangentX, aTangentY, aTangentZ);

   tangentAttrFn.setStorable(false);

   tangentAttrFn.setKeyable(false);

   tangentAttrFn.setReadable(true);

   tangentAttrFn.setWritable(false);

   addAttribute(aTangent);



   // CREATE AND ADD ".parameU" ATTRIBUTE:

   MFnNumericAttribute paramUAttrFn;

   aParamU = paramUAttrFn.create("paramU", "u", MFnNumericData::kDouble, 0.0);

   paramUAttrFn.setStorable(false);

   paramUAttrFn.setKeyable(false);

   paramUAttrFn.setReadable(true);

   paramUAttrFn.setWritable(false);

   addAttribute(aParamU);



   // CREATE AND ADD ".distance" ATTRIBUTE:

   MFnNumericAttribute distanceAttrFn;

   aDistance = distanceAttrFn.create("distance", "d", MFnNumericData::kDouble, 0.0);

   distanceAttrFn.setStorable(false);

   distanceAttrFn.setKeyable(false);

   distanceAttrFn.setReadable(true);

   distanceAttrFn.setWritable(false);

   addAttribute(aDistance);



   // DEPENDENCY RELATIONS FOR ".inCurve":

   attributeAffects(aInCurve, aPosition);

   attributeAffects(aInCurve, aPositionX);

   attributeAffects(aInCurve, aPositionY);

   attributeAffects(aInCurve, aPositionZ);

   attributeAffects(aInCurve, aNormal);

   attributeAffects(aInCurve, aNormalX);

   attributeAffects(aInCurve, aNormalY);

   attributeAffects(aInCurve, aNormalZ);

   attributeAffects(aInCurve, aTangent);

   attributeAffects(aInCurve, aTangentX);

   attributeAffects(aInCurve, aTangentY);

   attributeAffects(aInCurve, aTangentZ);

   attributeAffects(aInCurve, aParamU);

   attributeAffects(aInCurve, aDistance);



   // DEPENDENCY RELATIONS FOR ".inPosition":

   attributeAffects(aInPosition, aPosition);

   attributeAffects(aInPosition, aPositionX);

   attributeAffects(aInPosition, aPositionY);

   attributeAffects(aInPosition, aPositionZ);

   attributeAffects(aInPosition, aNormal);

   attributeAffects(aInPosition, aNormalX);

   attributeAffects(aInPosition, aNormalY);

   attributeAffects(aInPosition, aNormalZ);

   attributeAffects(aInPosition, aTangent);

   attributeAffects(aInPosition, aTangentX);

   attributeAffects(aInPosition, aTangentY);

   attributeAffects(aInPosition, aTangentZ);

   attributeAffects(aInPosition, aParamU);

   attributeAffects(aInPosition, aDistance);



   // DEPENDENCY RELATIONS FOR ".inPositionX":

   attributeAffects(aInPositionX, aPosition);

   attributeAffects(aInPositionX, aPositionX);

   attributeAffects(aInPositionX, aPositionY);

   attributeAffects(aInPositionX, aPositionZ);

   attributeAffects(aInPositionX, aNormal);

   attributeAffects(aInPositionX, aNormalX);

   attributeAffects(aInPositionX, aNormalY);

   attributeAffects(aInPositionX, aNormalZ);

   attributeAffects(aInPositionX, aTangent);

   attributeAffects(aInPositionX, aTangentX);

   attributeAffects(aInPositionX, aTangentY);

   attributeAffects(aInPositionX, aTangentZ);

   attributeAffects(aInPositionX, aParamU);

   attributeAffects(aInPositionX, aDistance);



   // DEPENDENCY RELATIONS FOR ".inPositionY":

   attributeAffects(aInPositionY, aPosition);

   attributeAffects(aInPositionY, aPositionX);

   attributeAffects(aInPositionY, aPositionY);

   attributeAffects(aInPositionY, aPositionZ);

   attributeAffects(aInPositionY, aNormal);

   attributeAffects(aInPositionY, aNormalX);

   attributeAffects(aInPositionY, aNormalY);

   attributeAffects(aInPositionY, aNormalZ);

   attributeAffects(aInPositionY, aTangent);

   attributeAffects(aInPositionY, aTangentX);

   attributeAffects(aInPositionY, aTangentY);

   attributeAffects(aInPositionY, aTangentZ);

   attributeAffects(aInPositionY, aParamU);

   attributeAffects(aInPositionY, aDistance);



   // DEPENDENCY RELATIONS FOR ".inPositionZ":

   attributeAffects(aInPositionZ, aPosition);

   attributeAffects(aInPositionZ, aPositionX);

   attributeAffects(aInPositionZ, aPositionY);

   attributeAffects(aInPositionZ, aPositionZ);

   attributeAffects(aInPositionZ, aNormal);

   attributeAffects(aInPositionZ, aNormalX);

   attributeAffects(aInPositionZ, aNormalY);

   attributeAffects(aInPositionZ, aNormalZ);

   attributeAffects(aInPositionZ, aTangent);

   attributeAffects(aInPositionZ, aTangentX);

   attributeAffects(aInPositionZ, aTangentY);

   attributeAffects(aInPositionZ, aTangentZ);

   attributeAffects(aInPositionZ, aParamU);

   attributeAffects(aInPositionZ, aDistance);



   return MS::kSuccess;

}





// COMPUTE METHOD'S DEFINITION:

MStatus closestPointOnCurveNode::compute(const MPlug &plug, MDataBlock &data)

{

   // DO THE COMPUTE ONLY FOR THE *OUTPUT* PLUGS THAT ARE DIRTIED:

   if ((plug == aPosition)  || (plug == aPositionX)  || (plug == aPositionY)  || (plug == aPositionZ)

    || (plug == aNormal) || (plug == aNormalX) || (plug == aNormalY) || (plug == aNormalZ)

    || (plug == aTangent) || (plug == aTangentX) || (plug == aTangentY) || (plug == aTangentZ)

	|| (plug == aParamU) || (plug == aDistance))

   {

      // READ IN ".inCurve" DATA:

      MDataHandle inCurveDataHandle = data.inputValue(aInCurve);

      MObject inCurve = inCurveDataHandle.asNurbsCurve();



      // READ IN ".inPositionX" DATA:

      MDataHandle inPositionXDataHandle = data.inputValue(aInPositionX);

      double inPositionX = inPositionXDataHandle.asDouble();



      // READ IN ".inPositionY" DATA:

      MDataHandle inPositionYDataHandle = data.inputValue(aInPositionY);

      double inPositionY = inPositionYDataHandle.asDouble();



      // READ IN ".inPositionZ" DATA:

      MDataHandle inPositionZDataHandle = data.inputValue(aInPositionZ);

      double inPositionZ = inPositionZDataHandle.asDouble();



      // GET THE CLOSEST POSITION, NORMAL, TANGENT, PARAMETER-U AND DISTANCE:

      MPoint inPosition(inPositionX, inPositionY, inPositionZ), position;

      MVector normal, tangent;

      double paramU, distance;

      MDagPath dummyDagPath;

      closestTangentUAndDistance(dummyDagPath, inPosition, position, normal, tangent, paramU, distance, inCurve);



      // WRITE OUT ".position" DATA:

      MDataHandle positionDataHandle = data.outputValue(aPosition);

      positionDataHandle.set(position.x, position.y, position.z);

      data.setClean(plug);



      // WRITE OUT ".normal" DATA:

      MDataHandle normalDataHandle = data.outputValue(aNormal);

      normalDataHandle.set(normal.x, normal.y, normal.z);

      data.setClean(plug);



      // WRITE OUT ".tangent" DATA:

      MDataHandle tangentDataHandle = data.outputValue(aTangent);

      tangentDataHandle.set(tangent.x, tangent.y, tangent.z);

      data.setClean(plug);



      // WRITE OUT ".paramU" DATA:

      MDataHandle paramUDataHandle = data.outputValue(aParamU);

      paramUDataHandle.set(paramU);

      data.setClean(plug);



      // WRITE OUT ".distance" DATA:

      MDataHandle distanceDataHandle = data.outputValue(aDistance);

      distanceDataHandle.set(distance);

      data.setClean(plug);

   }

   else

   {

      return MS::kUnknownParameter;

   }



   return MS::kSuccess;

}

